package com.xinyue.server.framework.handlermapping;

import com.xinyue.server.framework.message.GameMessageMeta;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 王广帅
 * @date 2021年01月26日 4:35 下午
 */
public class GameHandlerMappingManager {

    private static GameHandlerMappingManager instance = new GameHandlerMappingManager();


    private Logger logger = LoggerFactory.getLogger(GameHandlerMappingManager.class);

    private Map<MessageClassKey, GameMappingMethod> gameMappingMethodMap = new HashMap<>();
    private Map<MessageClassKey, Class<?>> messageClassMap = new HashMap<>();

    private GameHandlerMappingManager() {
    }

    public static GameHandlerMappingManager getInstance() {
        return instance;
    }

    private MessageClassKey addMessageClass(Class<?> clazz) {
        GameMessageMeta gameMessageMeta = clazz.getAnnotation(GameMessageMeta.class);
        if (gameMessageMeta == null) {
            throw new IllegalArgumentException("此消息类没有添加GameMessageMeta注解，class = " + clazz.getName());
        }
        MessageClassKey messageClassKey = new MessageClassKey(gameMessageMeta.messageId(), gameMessageMeta.messageType());
        if (!messageClassMap.containsKey(messageClassKey)) {
            messageClassMap.put(messageClassKey, clazz);
        } else {
            Class<?> oldExistClass = messageClassMap.get(messageClassKey);
            String msg = String.format("添加映射类：%s时，消息号：%s已存在，对应的类是：%s", clazz.getName(), gameMessageMeta.messageId(), oldExistClass.getName());
            throw new IllegalArgumentException(msg);
        }
        return messageClassKey;
    }

    public Class<? extends IGameMessage> getRequestClass(MessageClassKey messageClassKey) {
        Object value = messageClassMap.get(messageClassKey);
        return (Class<? extends IGameMessage>) value;
    }

    /**
     * 从Sring的容器中读取GameHandlerComponent标记的实例
     *
     * @param context
     */
    public void scanGameHandler(ApplicationContext context) {
        String[] handlerBeanNames = context.getBeanNamesForAnnotation(GameHandlerComponent.class);
        logger.debug("----->加载GameHandlerComponent的bean数量:{}", handlerBeanNames.length);
        for (String beanName : handlerBeanNames) {
            Object beanObj = context.getBean(beanName);
            //查找处理请求的方法
            Method[] methods = beanObj.getClass().getMethods();
            for (Method method : methods) {
                GameMapping gameMapping = method.getAnnotation(GameMapping.class);
                if (gameMapping != null) {
                    Class<?> gameMessageClass = gameMapping.value();
                    MessageClassKey classKey = addMessageClass(gameMessageClass);
                    GameMappingMethod gameMappingMethod = new GameMappingMethod(beanObj, method);
                    gameMappingMethodMap.put(classKey, gameMappingMethod);
                }
            }
        }
    }

    public void callMethod(GameChannelContext ctx, MessageClassKey messageClassKey, IGameMessage gameMessage) throws Exception {
        GameMappingMethod gameMappingMethod = gameMappingMethodMap.get(messageClassKey);
        if (gameMappingMethod == null) {
            throw new IllegalArgumentException("不存在此消息的处理方法,messageId:" + messageClassKey.getMessageId() + ", messageType:" + messageClassKey.getMessageType());
        }
        Method handlerMethod = gameMappingMethod.getHandlerMethod();
        handlerMethod.invoke(gameMappingMethod.getHandlerObj(), ctx, gameMessage);
    }
}
